"""
注意，优先队列（priority queue）也叫做堆（heap）。谈到优先队列时，一般强调其功能或应用，
谈到堆时，一般强调其树形结构，但这两个词是可以进行同义替换的，大部分时候不用做严格区分。
在Python中，我们使用内置库heapq来实现优先队列的相关操作。需要先导入heapq库。即
from heapq import *
from heapq import heapify, heappush, heappop    # 导入最常用的三个API
虽然优先队列的底层原理是用完全二叉树来实现的，但由于完全二叉树通过层序遍历（即树的BFS）可以得到序列化的结果（即数组），
故通常而言我们无需显式地构建出一棵完全二叉树来实现堆，而是使用heapq内置库来对一个列表进行堆化和堆操作。

"""

# 使用heapq内置库中的内置函数heapify()来实现一个列表的堆化。
# 所谓堆化，是指令一个列表按照堆排序的要求来排序的过程。
# 从单词heapify()也可以看出，这是一个动词，故该函数是功能对heap列表进行原地排序，没有返回值。
# 堆化/堆排序的时间复杂度是O(NlogN)
from heapq import *
heap = [1, 3, 4, 2]        # 构建一个叫做heap的列表
heapify(heap)              # 令heap堆化
print(heap)                # 输出[1, 2, 4, 3]，是heap按照堆排序后的结果

# 使用heapq内置库中的内置函数heappush(heap, element)来实现将元素element加入堆heap中。
heap = [1, 3, 4, 2]        # 构建一个叫做heap的列表
heapify(heap)              # 令heap堆化
heappush(heap, 5)          # 令元素5入堆
print(heap)                # 输出[1, 2, 4, 3, 5]，是5入堆后的结果
heappush(heap, 0)          # 令元素0入堆
print(heap)                # 输出[0, 2, 1, 3, 5, 4]，是0入堆后的结果

# 使用heapq内置库中的内置函数heappop(heap)来实现弹出堆heap的堆顶元素。
# 出堆操作的时间复杂度为O(logN)。heappop()函数是有返回值的，返回出堆的堆顶元素。
heap = [0, 1, 2, 3, 4, 5]  # 构建一个叫做heap的列表
heapify(heap)              # 令heap堆化
top = heappop(heap)        # 弹出堆顶元素
print(top, heap)           # 输出0和[1, 3, 2, 5, 4]，是堆顶元素0出堆后的结果
top = heappop(heap)        # 弹出堆顶元素
print(top, heap)           # 输出1和[2, 3, 4, 5]，是堆顶元素1出堆后的结果

# 堆顶元素总是位于列表heap索引为0的位置，故直接使用索引操作即可获得堆顶元素。
heap = [5, 4, 2, 0, 3, 1]  # 构建一个叫做heap的列表
heapify(heap)              # 令heap堆化
print(heap[0])             # 输出堆顶元素0

"""
小根堆是指较小值具有更高优先级的堆，在树形结构上体现为，每一个节点的值都小于其子节点的值。
大根堆是指较大值具有更高优先级的堆，在树形结构上体现为，每一个节点的值都大于其子节点的值。
在Python的heapq库中，默认的操作是构建小根堆。
如果想要构建一个大根堆，可以通过储存元素相反值的方式来构建一个伪大根堆，即实际上仍然按照小根堆来操作，但由于储存了相反数，原先的最大值会变成绝对值最大的最小值而储存在堆顶。如

"""
heap = [0, 1, 2, 3, 4, 5]      # 构建一个叫做heap的列表
heap = [-num for num in heap]  # 储存相反数
heapify(heap)                  # 令heap堆化，得到一个伪大根堆
top = -heappop(heap)           # 弹出堆顶元素，再取反，可以得到原heap中的最大值
print(top, heap)               # 输出5和[-4, -3, -2, 0, -1]，是堆顶元素-5出堆后的结果
heappush(heap, -10)            # 往堆中存入元素10，应该存入其相反数-10
print(heap)                    # 输出[-10, -3, -4, 0, -1, -2]，可以看到-10位于堆顶heap[0]的位置